package com.codi.bus.core.service.impl;

import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.util.DateUtils;
import com.codi.base.util.ListUtil;
import com.codi.base.util.MoneyUtils;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.ProfitDao;
import com.codi.bus.core.dao.UserBankDao;
import com.codi.bus.core.domain.Lookup;
import com.codi.bus.core.domain.Profit;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.domain.UserBank;
import com.codi.bus.core.resultModel.AssetsResult;
import com.codi.bus.core.resultModel.BaseResult;
import com.codi.bus.core.resultModel.ProfitResult;
import com.codi.bus.core.resultModel.WalletDetailResult;
import com.codi.bus.core.service.AssetsIncomeService;
import com.codi.bus.core.service.FundDetailService;
import com.codi.bus.core.service.WalletService;
import com.codi.bus.core.service.model.AssetFundModel;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.fundData.domain.FundMMYieldPerformance;
import com.codi.fundData.domain.SecurityProduct;
import com.codi.fundData.service.FundMMYieldPerformanceService;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by asus on 2018/5/14.
 */
@Transactional
@Service("assetsIncomeService")
@Slf4j
public class AssetsIncomeServiceImpl implements AssetsIncomeService {
    @Autowired
    private UserBankDao userBankDao;

    @Autowired
    private ProfitDao profitDao;

    @Autowired
    private FundDetailService fundDetailService;

    @Autowired
    private WalletService walletService;

    @Autowired
    private FundMMYieldPerformanceService fundMMYieldPerformanceService;

    @Override
    public BaseResult getProfit(Long userId, String fundCode, String type, Integer beginNum, Integer requestNum){
        Date dateTime = new Date();
        List<UserBank> userBankList = userBankDao.getListByUserId(userId);
        switch (type){
            case GlobalConstant.ALL_TIME:
                dateTime = null;
                break;
            case GlobalConstant.THIS_YEAR:
                //TODO  提到工具类
                Calendar calendar = Calendar.getInstance();
                int currentYear = calendar.get(Calendar.YEAR);
                calendar.clear();
                calendar.set(Calendar.YEAR, currentYear);
                dateTime = calendar.getTime();
                break;
            case GlobalConstant.THREE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            case GlobalConstant.ONE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            case GlobalConstant.ONE_WEEK:
                dateTime = DateUtils.addDay(dateTime,-7);
                break;
            default:
                dateTime = null;
        }
        Date queryTime = getBeginDate(dateTime);
        List<Profit> profits = new ArrayList<>();
        for (UserBank userBank : userBankList){

            List<Profit> profitTrades = profitDao.selectProfitByFundCode(Math.toIntExact(userId), userBank.getExternalTradeAccount(), fundCode, null);
            profits.addAll(profitTrades);
        }
        ProfitResult profitResult = new ProfitResult();
        BigDecimal accumIncome = new BigDecimal(0);
        BigDecimal allProfit = new BigDecimal(0);
        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();

        // 将基金按 基金编号和日期累加  不同交易账号累加
        for (Profit profit : profits){
            //profit.setDateTime(profit.getDateTime());
            String key = profit.getFundCode() + profit.getDateTime();
            if (map.containsKey(key)){
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(),profit.getProfitValue()));
                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(),profit.getAccumulateProfitValue()));
            }else {
                map.put(key,profit);
            }
        }
        for (String key : map.keySet()){
            profitsNew.add(map.get(key));
        }


        //按日期倒序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return 0 - o1No.compareTo(o2No);
            }
        });



        //这里  为了算  一段时间的累计收益 才搞得这么麻烦
        List<Profit> profitsByTime = new ArrayList<>();
        for (Profit profit : profitsNew) {
            if (profit.getDateTime().compareTo(DateUtils.formatDateTime(queryTime)) > 0){
                //累加 指定日期后 的 收益
                allProfit = MoneyUtils.add(allProfit,profit.getProfitValue());
                if (profit.getProfitValue() != null){
                    profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
                }
                if (profit.getAccumulateProfitValue() != null){
                    profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
                }
                profitsByTime.add(profit);
            }
        }
        profitResult.setTotalCount(profitsByTime.size());

        //如果  查到了  指定查询日期 中  所有日期 的 收益   就可以 通过累加 日收益 获取 当前区间的累计收益
        //如果  没有查到所有   则不能累加  需要取总收益     因为不取的话 累加会 少加一个 初始的 累计收益
        if (profitsNew.isEmpty()){
            accumIncome = allProfit;
        }else {
            if (dateTime == null || profitsNew.get(profitsNew.size() - 1).getDateTime().compareTo(DateUtils.formatDate(dateTime)) > 0){
                accumIncome = profitsNew.get(0).getAccumulateProfitValue();
            }else {
                accumIncome = allProfit;
            }
        }



        List<Profit> profitsReal = new ArrayList<>();
        for (int i = 1; i <= profitsByTime.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                profitsReal.add(profitsByTime.get(i - 1));
            }
        }
        profitResult.setProfits(profitsReal);
        profitResult.setAccumIncome(accumIncome);
        return profitResult;
    }

    @Override
    public BaseResult getPortfolioProfit(Long userId, String tradeAcco, String type, Integer beginNum, Integer requestNum){
        Date dateTime = new Date();
        // 展示收益的期限
        switch (type){
            case GlobalConstant.ALL_TIME:
                dateTime = null;
                break;
            case GlobalConstant.THIS_YEAR:
                //TODO  提到工具类
                Calendar calendar = Calendar.getInstance();
                int currentYear = calendar.get(Calendar.YEAR);
                calendar.clear();
                calendar.set(Calendar.YEAR, currentYear);
                dateTime = calendar.getTime();
                break;
            case GlobalConstant.ONE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            case GlobalConstant.THREE_MONTH:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            case GlobalConstant.ONE_WEEK:
                dateTime = DateUtils.addDay(dateTime,-7);
                break;
            default:
                dateTime = null;
        }

        Date queryTime = getBeginDate(dateTime);
        List<Profit> profits = profitDao.selectProfitByFundCode(Math.toIntExact(userId), tradeAcco, null, null);
        ProfitResult profitResult = new ProfitResult();
        BigDecimal accumIncome = new BigDecimal(0);
        BigDecimal allProfit = new BigDecimal(0);
        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();

        // 将组合按 交易账号和日期累加  一个组合一天的收益
        for (Profit profit : profits){
            //profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
            String key = profit.getTradeAcco() + profit.getDateTime();
            if (map.containsKey(key)){
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(),profit.getProfitValue()));
                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(),profit.getAccumulateProfitValue()));
            }else {
                map.put(key,profit);
            }
        }
        for (String key : map.keySet()){
            profitsNew.add(map.get(key));
        }
        //按日期倒序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return 0 - o1No.compareTo(o2No);
            }
        });

        //这里  为了算  一段时间的累计收益 才搞得这么麻烦
        List<Profit> profitsByTime = new ArrayList<>();
        for (Profit profit : profitsNew) {
            if (profit.getDateTime().compareTo(DateUtils.formatDateTime(queryTime)) > 0){
                //累加 指定日期后 的 收益
                allProfit = MoneyUtils.add(allProfit,profit.getProfitValue());
                if (profit.getProfitValue() != null){
                    profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
                }
                if (profit.getAccumulateProfitValue() != null){
                    profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
                }
                profitsByTime.add(profit);
            }
        }
        profitResult.setTotalCount(profitsByTime.size());

        //如果  查到了  指定查询日期 中  所有日期 的 收益   就可以 通过累加 日收益 获取 当前区间的累计收益
        //如果  没有查到所有   则不能累加  需要取总收益     因为不取的话 累加会 少加一个 初始的 累计收益
        if (profitsNew.isEmpty()){
            accumIncome = allProfit;
        }else if (dateTime == null || profitsNew.get(profitsNew.size() - 1).getDateTime().compareTo(DateUtils.formatDate(dateTime)) > 0){
            accumIncome = profitsNew.get(0).getAccumulateProfitValue();
        }else {
            accumIncome = allProfit;
        }


        List<Profit> profitsReal = new ArrayList<>();
        for (int i = 1; i <= profitsByTime.size(); i++) {
            if (i >= beginNum && i < requestNum + beginNum) {
                profitsReal.add(profitsByTime.get(i - 1));
            }
        }
        profitResult.setProfits(profitsReal);
        profitResult.setAccumIncome(accumIncome);
        return profitResult;
    }


    @Override
    public BaseResult getAccum(Long userId, String fundCode, String type){
        Date dateTime = new Date();
        List<UserBank> userBankList = userBankDao.getListByUserId(userId);
        switch (type){
            case GlobalConstant.ALL:
                dateTime = null;
                break;
            case GlobalConstant.YEAR:
                dateTime = DateUtils.addMondth(dateTime, -12);
                break;
            case GlobalConstant.HALF_YEAR:
                dateTime = DateUtils.addMondth(dateTime, -6);
                break;
            case GlobalConstant.SEASON:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            case GlobalConstant.MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            default:
                dateTime = null;
        }
        //
        dateTime = getBeginDate(dateTime);
        dateTime = DateUtils.addDay(dateTime,1);
        List<Profit> profits = new ArrayList<>();
        for (UserBank userBank : userBankList){
            List<Profit> profitTrades = profitDao.selectAccumulateByFundCode(Math.toIntExact(userId), userBank.getExternalTradeAccount(), fundCode, dateTime);
            profits.addAll(profitTrades);
        }
        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();
        for (Profit profit : profits){
            if (profit.getProfitValue() != null){
                profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            if (profit.getAccumulateProfitValue() != null){
                profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }

            //profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
        }
        // 将基金按 基金编号和日期累加  不同交易账号累加
        for (Profit profit : profits){
            String key = profit.getFundCode() + profit.getDateTime();
            if (map.containsKey(key)){
                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(),profit.getAccumulateProfitValue()));
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(), profit.getProfitValue()));
            }else {
                map.put(key,profit);
            }
        }
        for (String key : map.keySet()){
            profitsNew.add(map.get(key));
        }
        //按日期正序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return o1No.compareTo(o2No);
            }
        });
        BaseResult result = new BaseResult();
        result.setResult(profitsNew);
        return result;
    }

    @Override
    public BaseResult getPortfolioAccum(Long userId, String tradeAcco, String type){
        Date dateTime = new Date();
        // 展示收益的期限
        switch (type){
            case GlobalConstant.ALL:
                dateTime = null;
                break;
            case GlobalConstant.YEAR:
                dateTime = DateUtils.addMondth(dateTime, -12);
                break;
            case GlobalConstant.HALF_YEAR:
                dateTime = DateUtils.addMondth(dateTime, -6);
                break;
            case GlobalConstant.MONTH:
                dateTime = DateUtils.addMondth(dateTime, -1);
                break;
            case GlobalConstant.SEASON:
                dateTime = DateUtils.addMondth(dateTime, -3);
                break;
            default:
                dateTime = null;
        }
        //因为 5月31 号 是 初始数据  不能展示
        dateTime = getBeginDate(dateTime);
        dateTime = DateUtils.addDay(dateTime,1);
        List<Profit> profits = profitDao.selectAccumulateByFundCode(Math.toIntExact(userId), tradeAcco, null, dateTime);

        List<Profit> profitsNew = new ArrayList<>();
        Map<String, Profit> map = new HashMap();
        //格式化日期
        for (Profit profit : profits){
            if (profit.getProfitValue() != null){
                profit.setProfitValue(profit.getProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            if (profit.getAccumulateProfitValue() != null){
                profit.setAccumulateProfitValue(profit.getAccumulateProfitValue().setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            //profit.setDateTime(DateUtils.formatDate(DateUtils.stringToDateWithTime(profit.getDateTime())));
        }
        // 将组合按 交易账号和日期累加  一个组合一个累计收益
        for (Profit profit : profits){
            String key = profit.getTradeAcco() + profit.getDateTime();
            if (map.containsKey(key)){
                map.get(key).setAccumulateProfitValue(MoneyUtils.add(map.get(key).getAccumulateProfitValue(),profit.getAccumulateProfitValue()));
                map.get(key).setProfitValue(MoneyUtils.add(map.get(key).getProfitValue(),profit.getProfitValue()));
            }else {
                map.put(key,profit);
            }
        }
        for (String key : map.keySet()){
            profitsNew.add(map.get(key));
        }
        //按日期倒序排序
        Collections.sort(profitsNew, new Comparator<Profit>() {
            @Override
            public int compare(Profit o1, Profit o2) {
                String o1No = o1.getDateTime(), o2No = o2.getDateTime();
                return o1No.compareTo(o2No);
            }
        });
        BaseResult result = new BaseResult();
        result.setResult(profitsNew);
        return result;
    }

    @Override
    public WalletDetailResult getSevenProfitByFundCode(Long userId, String fundCode) throws BaseAppException {
        // 校验fundCode是否在T0列表中

        SecurityProduct product = fundDetailService.getSecurityProduct(fundCode);

        WalletDetailResult result = new WalletDetailResult();

        result.setFundName(product.getChiNameAbbr());
        result.setFundCode(fundCode);
        // 七日年化率
        //FundMMYieldPerformance perf = fundMMYieldPerformanceService.getFundMMYieldPerformance(product.getInnerCode());
        //result.setNetValueDate(perf.getTradingDay());
        //result.setLatestWeeklyYield(MoneyUtils.formatMoneyNoRound(perf.getLatestWeeklyYield(), 2));// 最近7日折算年收益率（%）
        //result.setDailyProfit(MoneyUtils.formatMoney(perf.getDailyProfit(), 4));

        // 最近七天的七日年化收益率(降序)
        walletService.setWeekYield(product, result);
        result.setSuccess(true);
        return result;
    }

    @Override
    public Date getBeginDate(Date dateTime){
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, 2018);
        c.set(Calendar.MONTH, 4);
        c.set(Calendar.DATE, 31);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        Date date = c.getTime();
        if (dateTime == null){
            return date;
        }
        if (dateTime.before(date)){
            return date;
        }
        return dateTime;

    }
}
